/*
 * The MIT License (MIT)
 * 
 * Copyright (c) 2014 Krzysztof Narkiewicz <krzysztof.narkiewicz@ezaquarii.com>
 * 
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 * 
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 * 
 */

%skeleton "lalr1.cc" /* -*- C++ -*- */
%require "3.0"
%defines
%define api.parser.class { Parser }

%define api.token.constructor
%define api.value.type variant
%define parse.assert
%define api.namespace { CustomParser }
%code requires
{
    #include <iostream>
    #include <string>
    #include <vector>
    #include <deque>
    #include <stdint.h>
    #include "command.h"
    #include "syntax_node.h"

    using namespace std;

    namespace CustomParser {
        class Scanner;
        class Interpreter;
    }
}

// Bison calls yylex() function that must be provided by us to suck tokens
// from the scanner. This block will be placed at the beginning of IMPLEMENTATION file (cpp).
// We define this function here (function! not method).
// This function is called only inside Bison, so we make it static to limit symbol visibility for the linker
// to avoid potential linking conflicts.
%code top
{
    #include <iostream>
    #include "scanner.h"
    #include "parser.hpp"
    #include "interpreter.h"
    #include "location.hh"
    
    // yylex() arguments are defined in parser.y
    static CustomParser::Parser::symbol_type yylex(CustomParser::Scanner &scanner, CustomParser::Interpreter &driver) {
        return scanner.get_next_token();
    }
    
    // you can accomplish the same thing by inlining the code using preprocessor
    // x and y are same as in above static function
    // #define yylex(x, y) scanner.get_next_token()
    
    using namespace CustomParser;
}

%lex-param { CustomParser::Scanner &scanner }
%lex-param { CustomParser::Interpreter &driver }
%parse-param { CustomParser::Scanner &scanner }
%parse-param { CustomParser::Interpreter &driver }
%locations
%define parse.trace
%define parse.error verbose

%define api.token.prefix {TOKEN_}

%token END 0 "end of file"


%token <std::string> STRUCT_BEGIN
%token <std::string> IDENTIFIER
%token <std::string> DOUBLE
%token <std::string> INTEGER
%token <std::string> STRING
%token <std::string> EQUAL
%token <std::string> CEQ
%token <std::string> CNE
%token <std::string> CLT
%token <std::string> CLE
%token <std::string> CGT
%token <std::string> CGE
%token <std::string> LPAREN
%token <std::string> RPAREN
%token <std::string> LBRACE
%token <std::string> RBRACE
%token <std::string> DOT
%token <std::string> COMMA
%token <std::string> PLUS
%token <std::string> MINUS
%token <std::string> MUL
%token <std::string> DIV
%token <std::string> SEMICOLON

%token <std::string> RETURN

%start program

%type <std::string> numeric ident comparison

%type <SyntaxNode> expr template_parameters func_decl_args var_decl func_decl stmt stmts block struct_decl

%%

program : 
END
{
    return -1;
}
| expr {
    driver.addSyntaxNode($1);
    return 0;
}
| func_decl {
    driver.addSyntaxNode($1);
    return 0;
}
| struct_decl {
    driver.addSyntaxNode($1);
    return 0;
}
;

struct_decl : STRUCT_BEGIN expr block SEMICOLON
    {
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_child($3);
        $$.push_back_rear_ele($4);

        // std::cout << "struct_decl: " << $1 << " " << $2 << " " << $3 << " " << $4 << std::endl;
        
    }
    ;

block : LBRACE stmts RBRACE { 
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.move_child($2);
        $$.push_back_rear_ele($3);
    }
    | LBRACE RBRACE { 
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.push_back_rear_ele($2);
    }
    ;

stmts : stmt { 
        $$ = SyntaxNode();
        $$.push_child($1);
    }
    | stmts stmt { 
        $$ = SyntaxNode(); 
        $$.move_child($1);
        $$.push_child($2); 
    }
    | func_decl { 
        $$ = SyntaxNode(); 
        $$.push_child($1);
    }
    | stmts func_decl { 
        $$ = SyntaxNode(); 
        $$.move_child($1);
        $$.push_child($2);
    }
    ;

stmt : SEMICOLON { $$ = SyntaxNode(); }
    | expr SEMICOLON { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2); 
    }
    | var_decl SEMICOLON { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
    }
    | RETURN SEMICOLON {
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
    }
    | RETURN expr SEMICOLON {
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_back_front_ele($3);
     }
    ;

var_decl : ident ident { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);  
        // std::cout << "var_decl: " << $1 << " " << $2 << std::endl;
    }
    | ident ident EQUAL expr 
    { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_back_front_ele($3);
        $$.push_back_front_ele($4);
    }
    | ident CLT template_parameters CGT expr { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_back_front_ele($3);
        $$.push_back_front_ele($4);
        $$.push_back_front_ele($5);
    }
    ;

func_decl : ident ident LPAREN func_decl_args RPAREN block {
    $$ = SyntaxNode();
    $$.push_back_front_ele($1);
    $$.push_back_front_ele($2);
    $$.push_back_front_ele($3);
    $$.push_back_front_ele($4);
    $$.push_back_front_ele($5);
    $$.push_child($6);
}

func_decl_args : /*blank*/  { $$ = SyntaxNode(); }
    | var_decl { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
     }
    | func_decl_args COMMA var_decl { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_back_front_ele($3);
     }
    ;

template_parameters : ident { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1); 
    }
    | template_parameters COMMA ident { 
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_back_front_ele($3); 
    }

expr : ident { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1);
    }
    | numeric { 
        $$ = SyntaxNode(); 
        $$.push_back_front_ele($1); 
    }
    | STRING { 
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
    }
    | ident EQUAL expr {
        $$ = SyntaxNode();
        $$.push_back_front_ele($1);
        $$.push_back_front_ele($2);
        $$.push_back_front_ele($3);
    }
    ;

ident : IDENTIFIER { 
        $$ = $1;
    }
    ;

numeric : INTEGER { 
        $$ = $1; 
    }
    | DOUBLE { 
        $$ = $1;  
    }
    ;

comparison : CEQ { 
        $$ = $1;
    }
    | CNE { 
        $$ = $1;
    }
    | CLT { 
        $$ = $1;
    }
    | CLE { 
        $$ = $1;
    }
    | CGT { 
        $$ = $1;
    }
    | CGE { 
        $$ = $1;  
    }
    | PLUS { 
        $$ = $1;
    }
    | MINUS { 
        $$ = $1;
    }
    | MUL { 
        $$ = $1;
    }
    | DIV { 
        $$ = $1;
    }
    ;
    
%%

// Bison expects us to provide implementation - otherwise linker complains
void CustomParser::Parser::error(const location &loc , const std::string &message) {
        
        // Location should be initialized inside scanner action, but is not in this example.
        // Let's grab location directly from driver class.
	// cout << "Error: " << message << endl << "Location: " << loc << endl;
	
        cout << "Error: " << message << endl << "Error location: " << driver.location() << endl;
}
